package com.warrior.main;

import java.io.IOException;

import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.warrior.bluetooth.BluetoothHandler;
import com.warrior.bluetooth.BluetoothHandler.BluetoothServerThread;
import com.warrior.bluetooth.BluetoothHandler.ICreateSocket;
import com.warrior.bluetooth.CommHandler;
import com.warrior.bluetooth.CommHandler.IDateReceive;
import com.warrior.bluetooth.MyMessage;
import com.warrior.bluetooth.Sync;

public class MyApp extends Application implements IDateReceive,ICreateSocket{

	private MyFacebook fb;
	private CommHandler commHandler;
	private boolean isServer;
	private long timeAir;
	private BluetoothHandler bt;
	private Sync sync;
	private String myDeviceName,competitorDeviceName;
	
	private IDataRecevieGame iDataReceiveGame;
	private IDataReceiveSync iDataRecevieSync;
	private ISelectGame iSelectGame;
	private IBluetoothChanged iBluetoothChanged;
	private APP_STATES state;
	private BluetoothServerThread server;
	public static long DATA_ARRIVED = 50000;
	
	
	public MyApp(){
		fb = new MyFacebook(this);
		setMyDeviceName(android.os.Build.DEVICE);
	}
	
	public long getTimeAir()
	{
		return timeAir;
	}
	public APP_STATES getState(){
		return state;
	}
	public CommHandler getCommHandler()
	{
		return commHandler;
	}
	public MyFacebook getFacebook(){
		return fb;
	}
	public BluetoothHandler getBluetoothHandler(){
		return bt;
	}
	public Sync getSync() {
		return sync;
	}
	public String getMyDeviceName() {
		return myDeviceName;
	}
	public String getCompetitorDeviceName() {
		return competitorDeviceName;
	}
	public boolean isConnectedWithOtherDevice() {
		if(commHandler == null){
			return false;
		}
		return commHandler.isConnected();
	}
	public boolean isServer(){
		return isServer;
	}
	public void setBluetoothChangedListener(IBluetoothChanged iBluetoothChanged) {
		this.iBluetoothChanged = iBluetoothChanged;
	}
	public void setDataReceiveSelectGameListener(ISelectGame iSelectGame){
		this.iSelectGame = iSelectGame;
	}

	public void setDataRecevieSyncListener(IDataReceiveSync iDataReceiveSync){
		this.iDataRecevieSync = iDataReceiveSync;
	}
	public void setDataRecevieGameListener(IDataRecevieGame iDataRecieveGame){
		this.iDataReceiveGame = iDataRecieveGame;
	}
	public void setCommHndler(CommHandler commHandler){
		this.commHandler = commHandler;
	}
	public void setBluetoothHandler(BluetoothHandler bt){
		this.bt = bt;
	}
	public void setServer(boolean isServer){
		this.isServer = isServer;
		
	}
	public void setTimeAir(long timeAir){
		this.timeAir = timeAir;
	}
	public void setState(APP_STATES state) {
		this.state = state;
	}
	public void setMyDeviceName(String myDeviceName) {
		this.myDeviceName = myDeviceName;
	}
	public void setCompetitorDeviceName(String competitorDeviceName) {
		this.competitorDeviceName = competitorDeviceName;
	}
	public void killServer(){
		if(server != null){
			server.close();
		}
	}
	public void buildBluetoothHandler(){
		bt = new BluetoothHandler(this); 
		registerBluetooth();
	    if(bt.isEnabled()){
	    	try{
	    		turnedOnBluetooth();
				bt.makeDiscoverable();
				Log.d(MyLog.APP,"server wait");
	    	} catch (Exception e) {
				Log.d(MyLog.APP,"when start listing socket " + e.getMessage());
			}
	    }
	}
	private void registerBluetooth(){
		// we do not register to bluetooth connected because we use with iCreatedSocket interface 
		// MyApp class implements ICreateSocket 
		bt.registerBluetoothConnected(BluetootChangedhReceiver);
		
		bt.registerBluetoothDisconnected(BluetootChangedhReceiver);
		bt.registerBluetoothStateChanged(BluetootChangedhReceiver);
	}
	public void unregisterBluetooth(){
		unregisterReceiver(BluetootChangedhReceiver);
	}
	private void bluetoothConnected(String otherDeviceName){
		//register application to receive data 
		if(commHandler != null){
			commHandler.setDateReceiveListener(this);
			commHandler.startReceiveDataListener();
		}
		setState(APP_STATES.SYNC);
		sync = new Sync(this);
		// call to current activity with message bluetooth connected 
		String message = "you are connected to " + otherDeviceName;
		iBluetoothChanged.bluetoothStateConnectionChanged(true,message);
		if(isServer()){
			sync.startSync();
		}
	}
	public void createdSocket(BluetoothSocket bluetoothSocket) {
		// this method called when client connect to server or when server connect to client
		if(commHandler == null)
		{
			Log.d(MyLog.APP, "created server socket");
			try {
				// create CommHandler class  for connection with other device
				commHandler = new CommHandler(this,bluetoothSocket);
	    		bluetoothConnected(bluetoothSocket.getRemoteDevice().getName());
			} catch (IOException e) {
				iBluetoothChanged.bluetoothStateConnectionChanged(false,e.getMessage());
				Log.d(MyLog.APP_EXCEPTION, "IOException when created commHandler message: " + e.getMessage());
			}
		}
	}
	public BroadcastReceiver BluetootChangedhReceiver = new BroadcastReceiver() {
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
		    if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
		    	closeConnection();
		    	Log.d("MyApp","disconnected");
		    }
		    else if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){
		    	// to bluetooth there are 4 modes
		    	// turning off, off, turning on, on
		    	// we use in two state turning off and turning on
		    	int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                        BluetoothAdapter.ERROR);
		    	Log.d(MyLog.APP,"action state changed = " + state);
		    	switch (state) {
		            case BluetoothAdapter.STATE_TURNING_OFF:
			    		closeConnection();
			    		server = null;
			    		// becuase sync create after create connection with other device 
			    		if(sync != null){
			    			sync.resetSync();
			    		}
		                break;
		            case BluetoothAdapter.STATE_ON:
		            	turnedOnBluetooth();
		            	break;
	            }
		    	iBluetoothChanged.bluetoothStateChanged(state);
		    }
		}
	};
	private void turnedOnBluetooth(){
		try {
        	// create server
    		isServer = true;
			server = bt.createServer();
			bt.setCreatedServerSocketListener(MyApp.this);
			// the server is opened and wait to connect in new thread
			server.startListeningSocket();
			Log.d(MyLog.APP,"server wait");
    	} catch (Exception e) {
			Log.d(MyLog.APP,"when start listing socket " + e.getMessage());
		}
	}
	public void closeConnection(){
		if(commHandler != null){
			commHandler.writeToRmoteDevice(CommHandler.DISCONNECTED);
	    	commHandler.closeConnection();
			commHandler = null;
		}
		bt.setDisable();
		iBluetoothChanged.bluetoothStateConnectionChanged(false,"connection closed");
	}
	public void dataReceive(MyMessage myMessage){
		// if state of this device not equals to state of other device save data
		// in SaveMyMessages class and read all data from class when application move to next state
		if(state != myMessage.getState()){
			Log.d(MyLog.APP,"state not compatible state of this device:" + state +
					"state of other device is:" + myMessage.getState());
			return;
		}
		// if state of this device equals to state of other device we can to continue and transfer data.
		switch(state){
			case SYNC:{
				if(iDataRecevieSync != null){
					if(myMessage.isIncludeCallback()){
						commHandler.writeToRmoteDevice(MyApp.DATA_ARRIVED);
					}
					iDataRecevieSync.dataRecevieSync(myMessage);
				}
				Log.d(MyLog.APP,"in follwiong state SYNC");
				break;
			}
			case SELECT_GAME:{
				if(iSelectGame != null){
					if(myMessage.isIncludeCallback()){
						commHandler.writeToRmoteDevice(MyApp.DATA_ARRIVED);
					}
					Long receiveData = myMessage.getLData();
					iSelectGame.dataReceiveSelectGame(receiveData);
				}
				Log.d(MyLog.APP,"in follwiong state SELECT_GAME");
				break;
			}
			case RUN_GAME:{
				if(iDataReceiveGame != null){
					if(myMessage.isIncludeCallback()){
						commHandler.writeToRmoteDevice(MyApp.DATA_ARRIVED);
					}
					Long receiveData = myMessage.getLData();
					iDataReceiveGame.dataReceiveGame(receiveData);
				}
				Log.d(MyLog.APP,"in following state: RUN_GAME" );
				break;
			}
		
		}
	}
	public interface IBluetoothChanged{
		void bluetoothStateConnectionChanged(boolean isConnected,String message);
		void bluetoothStateChanged(int state);
	}
	public interface ISelectGame{
		void dataReceiveSelectGame(Long typeGame);
	}
	public interface IDataReceiveSync {
		void dataRecevieSync(MyMessage myMessage);
	}	
	public interface IDataRecevieGame {
		void dataReceiveGame(long data);
	}
	static public enum APP_STATES{
		SYNC,
		SELECT_GAME,
		RUN_GAME
	}
	
}
